# 角色
import pygame
from .. import tools, setup
from .. import constants as C
import json
import os

class Player(pygame.sprite.Sprite):  # 继承精灵类
    def __init__(self, name):
        pygame.sprite.Sprite.__init__(self)
        self.name = name
        self.load_data()
        self.setup_states()
        self.setup_velocities()
        self.setup_timers()
        self.load_images()

    def load_data(self):
        file_name = self.name + '.json'
        file_path = os.path.join('source/data/player', file_name)
        with open(file_path) as f:
            self.player_data = json.load(f)


    def setup_states(self):  # 角色状态
        self.state = 'stand'
        self.face_right = True
        self.dead = False
        self.big = False
        self.can_jump = True

    def setup_velocities(self):  # 设置速率
        speed = self.player_data['speed']  # 读出json文件中速度数据
        self.x_vel = 0
        self.y_vel = 0  # x轴和y轴上的速度分量

        self.max_walk_vel = speed['max_walk_speed']
        self.max_run_vel = speed['max_run_speed']
        self.max_y_vel = speed['max_y_velocity']  # velocity速度
        self.jump_vel = speed['jump_velocity']
        self.walk_accel = speed['walk_accel']  # accelorate加速
        self.run_accel = speed['run_accel']
        self.turn_accel = speed['turn_accel']  # turnover转身
        self.gravity = C.GRAVITY  # 全局重力加速度
        self.anti_gravity = C.ANTI_GRAVITY

        self.max_x_vel = self.max_walk_vel
        self.x_accel = self.walk_accel

    def setup_timers(self):
        self.walking_timer = 0
        self.transition_timer = 0
        self.death_timer = 0

    def load_images(self):
        sheet = setup.GRAPHICS['mario_bros']
        frame_rects = self.player_data['image_frames']

        self.right_small_normal_frames = []
        self.left_small_normal_frames = []

        self.small_normal_frames = [self.right_small_normal_frames, self.left_small_normal_frames]

        self.all_frames = [
            self.right_small_normal_frames,
            self.left_small_normal_frames,
        ]

        self.right_frames = self.right_small_normal_frames
        self.left_frames = self.left_small_normal_frames

        for group, group_frame_rects in frame_rects.items():
            for frame_rect in group_frame_rects:
                right_image = tools.get_image(sheet, frame_rect['x'], frame_rect['y'],
                                              frame_rect['width'], frame_rect['height'], (0, 0, 0), C.PLAYER_MULTI)
                left_image = pygame.transform.flip(right_image, True, False)
                if group == 'right_small_normal':
                    self.right_small_normal_frames.append(right_image)
                    self.left_small_normal_frames.append(left_image)



        self.frame_index = 0
        self.frames = self.right_frames
        self.image = self.frames[self.frame_index]
        self.rect = self.image.get_rect()

    def update(self, keys):
        self.current_time = pygame.time.get_ticks()
        self.handle_states(keys)

    def handle_states(self, keys):

        self.can_jump_or_not(keys)

        if self.state == 'stand':
            self.stand(keys)
        elif self.state == 'walk':
            self.walk(keys)
        elif self.state == 'jump':
            self.jump(keys)
        elif self.state == 'fall':
            self.fall(keys)
        elif self.state == 'die':
            self.die(keys)

        if self.face_right:
            self.image = self.right_frames[self.frame_index]
        else:
            self.image = self.left_frames[self.frame_index]

    def can_jump_or_not(self, keys):
        if not keys[pygame.K_UP]:
            self.can_jump = True

    def stand(self, keys):
        self.frame_index = 0
        self.x_vel = 0
        self.y_vel = 0
        if keys[pygame.K_RIGHT]:
            self.face_right = True
            self.state = 'walk'
        elif keys[pygame.K_LEFT]:
            self.face_right = False
            self.state = 'walk'
        elif keys[pygame.K_UP] and self.can_jump:
            self.state = 'jump'
            self.y_vel = self.jump_vel

    def walk(self, keys):
        self.max_x_vel = self.max_walk_vel
        self.x_accel = self.walk_accel

        if keys[pygame.K_UP] and self.can_jump:
            self.state = 'jump'
            self.y_vel = self.jump_vel

        if self.current_time - self.walking_timer > 100:
            if self.frame_index < 3:   # 123帧为步行帧，在这三帧中切换
                self.frame_index += 1
            else:
                self.frame_index = 1
            self.walking_timer = self.current_time
        # 当Mario向左移动时按下右键，那么运动状态应该是先刹车；当Mario向右时按下右键，那么状态应该是加速
        # Mario往右行走，速度方向为正
        if keys[pygame.K_RIGHT]:  # 右键按下时，马里奥面部朝右
            self.face_right = True
            if self.x_vel < 0:
                self.frame_index = 5 # 代表刹车帧
                self.x_accel = self.turn_accel
            self.x_vel = self.calc_vel(self.x_vel, self.x_accel, self.max_x_vel, True)
        elif keys[pygame.K_LEFT]:
            self.face_right = False
            # 脸朝右时按下左键，由于速度大于0，则会显示刹车
            if self.x_vel > 0:
                self.frame_index = 5
                self.x_accel = self.turn_accel
            self.x_vel = self.calc_vel(self.x_vel, self.x_accel, self.max_x_vel, False)
        else:  # 当没有按键的时候，将速度减下来同时将状态变更为最初的站立状态
            if self.face_right:
                self.x_vel -= self.x_accel
                if self.x_vel < 0:
                    self.x_vel = 0
                    self.state = 'stand'
            else:
                self.x_vel += self.x_accel
                if self.x_vel > 0:
                    self.x_vel = 0
                    self.state = 'stand'

    def jump(self, keys):
        self.frame_index = 4  # 起跳帧
        self.y_vel += self.anti_gravity
        self.can_jump = False

        if self.y_vel >= 0:
            self.state = 'fall'

        if not keys[pygame.K_UP]:
            self.state = 'fall'


    def fall(self, keys):
        self.y_vel = self.calc_vel(self.y_vel, self.gravity, self.max_y_vel)

        # if self.rect.bottom > C.GROUND_HEIGHT:
        #     self.rect.bottom = C.GROUND_HEIGHT
        #     self.y_vel = 0
        #     self.state = 'walk'

    def die(self, keys):
        self.rect.y += self.y_vel
        self.y_vel += self.anti_gravity

    def go_die(self):
        self.dead = True
        self.y_vel = self.jump_vel
        self.frame_index = 6
        self.state = 'die'
        self.death_timer = self.current_time

    def calc_vel(self, vel, accel, max_vel, is_positive=True):
        if is_positive:
            return min(vel + accel, max_vel)
        # Mario往右行走，速度方向为正，每次都加上一个加速度，同时最快不超过最大速度
        else:
            return max(vel - accel, -max_vel)
        # 反之加上负的加速度，同时不小于负的最大速度
